package com.example.graphic.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.graphic.AI.*;
import com.example.graphic.entity.Copywriting;
import com.example.graphic.entity.Image;
import com.example.graphic.entity.ImageTag;
import com.example.graphic.entity.Tag;
import com.example.graphic.mapper.CopywritingMapper;
import com.example.graphic.mapper.ImageMapper;
import com.example.graphic.mapper.ImageTagMapper;
import com.example.graphic.mapper.TagMapper;
import com.example.graphic.model.dto.ImageQueryDTO;
import com.example.graphic.model.dto.TagWithImageIdDTO;
import com.example.graphic.service.ImageService;
import com.example.graphic.service.OssService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.example.graphic.model.vo.Result;
/**
 * 图片服务实现类
 */
@Slf4j
@Service
public class ImageServiceImpl extends ServiceImpl<ImageMapper, Image> implements ImageService {

    @Autowired
    private ImageMapper imageMapper;

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private CopywritingMapper copywritingMapper;

    @Autowired
    private ImageTagMapper imageTagMapper;

    @Autowired
    private OssService ossService;

    @Autowired
    private ClassifyClient classifyClient;

    @Autowired
    private ImageDescriptionClient imageDescriptionClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> uploadImages(List<MultipartFile> files, Long userId) {
        if (CollectionUtils.isEmpty(files)) {
            log.warn("未提供任何文件进行上传");
            return Collections.emptyList();
        }

        // 过滤有效的图片文件
        List<MultipartFile> validFiles = files.stream()
                .filter(file -> {
                    if (file.isEmpty()) {
                        log.warn("跳过空文件: {}", file.getOriginalFilename());
                        return false;
                    }
                    
                    String contentType = file.getContentType();
                    if (contentType == null || !contentType.startsWith("image/")) {
                        log.warn("跳过非图片文件: {}, 文件类型: {}", 
                                file.getOriginalFilename(), contentType);
                        return false;
                    }
                    
                    return true;
                })
                .collect(Collectors.toList());

        if (validFiles.isEmpty()) {
            log.warn("未找到有效的图片文件进行上传");
            return Collections.emptyList();
        }

        try {
            // 1. 图片调用OSS上传并获取URL
            MultipartFile[] fileArray = validFiles.toArray(new MultipartFile[0]);
            List<String> uploadUrls = ossService.uploadFiles(fileArray);
            log.info("成功上传 {} 张图片到OSS", uploadUrls.size());

            // 2. 调用classifyClient获取每个图片的所有标签
            List<List<String>> allImageTags;

            // 根据图片数量选择处理方式：多张图片使用并发处理，单张图片使用顺序处理
            if (validFiles.size() > 1) {
                log.info("检测到多张图片 ({}张)，使用并发处理", validFiles.size());
                allImageTags = processClassificationConcurrently(validFiles, uploadUrls);
            } else {
                log.info("检测到单张图片，使用顺序处理");
                allImageTags = processClassificationSequentially(validFiles, uploadUrls);
            }
            System.out.println(allImageTags);
            // 3. 将所有标签检查并插入标签表
            Set<String> allTagNames = allImageTags.stream()
                    .flatMap(List::stream)
                    .collect(Collectors.toSet());
            
            Map<String, Long> tagNameToIdMap = ensureTagsExist(allTagNames);
            log.info("处理了 {} 个不同的标签", tagNameToIdMap.size());

            // 4. 图片属性填充并插入图片表
            List<Long> imageIds = new ArrayList<>();
            for (int i = 0; i < validFiles.size() && i < uploadUrls.size(); i++) {
                MultipartFile file = validFiles.get(i);
                String uploadUrl = uploadUrls.get(i);
                
                Image image = new Image();
                image.setUserId(userId == null? 1l:userId);
                image.setFilePath(uploadUrl);
                image.setFileName(file.getOriginalFilename());
                image.setUploadTime(LocalDateTime.now());
                image.setVisitNum(0L);
                
                // 插入图片记录
                imageMapper.insert(image);
                imageIds.add(image.getId());
                
                log.info("插入图片记录: ID={}, 文件名={}", image.getId(), image.getFileName());
            }

            // 5. 将图片与标签关联表填充
            for (int i = 0; i < imageIds.size() && i < allImageTags.size(); i++) {
                Long imageId = imageIds.get(i);
                List<String> imageTags = allImageTags.get(i);
                
                // 为每个图片创建标签关联
                for (String tagName : imageTags) {
                    Long tagId = tagNameToIdMap.get(tagName);
                    if (tagId != null) {
                        ImageTag imageTag = new ImageTag();
                        imageTag.setImageId(imageId);
                        imageTag.setTagId(tagId);
                        
                        imageTagMapper.insert(imageTag);
                    }
                }
                
                log.info("为图片 {} 创建了 {} 个标签关联", imageId, imageTags.size());
            }

            log.info("图片上传完成，共处理 {} 张图片", uploadUrls.size());
            return uploadUrls;

        } catch (Exception e) {
            log.error("图片上传处理失败", e);
            throw new RuntimeException("图片上传失败: " + e.getMessage(), e);
        }
    }

    /**
     * 对单个图片进行分类处理
     * @param imageUrl 图片URL
     * @param fileName 文件名（用于日志）
     * @return 标签列表
     */
    private List<String> classifyImage(String imageUrl, String fileName) {
        try {
            // 创建分类请求，使用图片URL
            ClassifyRequest request = new ClassifyRequest(imageUrl);

            // 调用分类服务
            ClassifyResponse response = classifyClient.execute(request);

            // 解析标签数据
            List<String> imageTags = parseTagsFromResponse(response);

            log.info("图片 {} (URL: {}) 识别到 {} 个标签", fileName, imageUrl, imageTags.size());

            return imageTags;

        } catch (Exception e) {
            log.error("图片 {} 标签识别失败: {}", fileName, e.getMessage());
            // 识别失败时返回空标签列表
            return new ArrayList<>();
        }
    }

    /**
     * 顺序处理图片分类
     * @param validFiles 有效文件列表
     * @param uploadUrls 上传URL列表
     * @return 所有图片的标签列表
     */
    private List<List<String>> processClassificationSequentially(List<MultipartFile> validFiles, List<String> uploadUrls) {
        List<List<String>> allImageTags = new ArrayList<>();

        for (int i = 0; i < validFiles.size() && i < uploadUrls.size(); i++) {
            MultipartFile file = validFiles.get(i);
            String imageUrl = uploadUrls.get(i);

            List<String> imageTags = classifyImage(imageUrl, file.getOriginalFilename());
            allImageTags.add(imageTags);
        }

        return allImageTags;
    }

    /**
     * 并发处理图片分类
     * @param validFiles 有效文件列表
     * @param uploadUrls 上传URL列表
     * @return 所有图片的标签列表
     */
    private List<List<String>> processClassificationConcurrently(List<MultipartFile> validFiles, List<String> uploadUrls) {
        ExecutorService executor = Executors.newFixedThreadPool(Math.min(validFiles.size(), 10));

        try {
            log.info("开始并发处理 {} 张图片的分类", validFiles.size());
            long startTime = System.currentTimeMillis();

            // 创建CompletableFuture列表
            List<CompletableFuture<List<String>>> futures = new ArrayList<>();

            for (int i = 0; i < validFiles.size() && i < uploadUrls.size(); i++) {
                final int index = i;
                final MultipartFile file = validFiles.get(i);
                final String imageUrl = uploadUrls.get(i);

                CompletableFuture<List<String>> future = CompletableFuture
                    .supplyAsync(() -> classifyImage(imageUrl, file.getOriginalFilename()), executor)
                    .orTimeout(30, TimeUnit.SECONDS)
                    .exceptionally(throwable -> {
                        log.error("图片 {} 并发分类处理异常: {}", file.getOriginalFilename(), throwable.getMessage());
                        return new ArrayList<>();
                    });

                futures.add(future);
            }

            // 等待所有任务完成并收集结果，保持顺序
            List<List<String>> allImageTags = new ArrayList<>();
            for (CompletableFuture<List<String>> future : futures) {
                try {
                    allImageTags.add(future.get());
                } catch (Exception e) {
                    log.error("获取并发分类结果失败: {}", e.getMessage());
                    allImageTags.add(new ArrayList<>());
                }
            }

            long endTime = System.currentTimeMillis();
            log.info("并发处理完成，耗时: {} ms", endTime - startTime);

            return allImageTags;

        } catch (Exception e) {
            log.error("并发处理失败，回退到顺序处理: {}", e.getMessage());
            return processClassificationSequentially(validFiles, uploadUrls);
        } finally {
            // 确保线程池正确关闭
            executor.shutdown();
            try {
                if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                    executor.shutdownNow();
                }
            } catch (InterruptedException e) {
                executor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * 从分类响应中解析标签
     * @param response 分类响应
     * @return 标签列表
     */
    private List<String> parseTagsFromResponse(ClassifyResponse response) {
        if (response == null || !response.isSuccess()) {
            return new ArrayList<>();
        }
        
        try {
            // 直接使用ClassifyResponse提供的getAllTags()方法
            // 该方法会将data中的两个列表合并，返回所有标签
            return response.getAllTags();
        } catch (Exception e) {
            log.warn("解析标签数据失败: {}", e.getMessage());
            return new ArrayList<>();
        }
    }

    /**
     * 确保标签存在于数据库中，不存在则创建
     *
     * @param tagNames 标签名称集合
     * @return 标签名称到ID的映射
     */
    private Map<String, Long> ensureTagsExist(Set<String> tagNames) {
        Map<String, Long> tagNameToIdMap = new HashMap<>();

        if (CollectionUtils.isEmpty(tagNames)) {
            return tagNameToIdMap;
        }

        // 查询已存在的标签
        LambdaQueryWrapper<Tag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Tag::getName, tagNames);
        List<Tag> existingTags = tagMapper.selectList(queryWrapper);

        // 记录已存在的标签
        for (Tag tag : existingTags) {
            tagNameToIdMap.put(tag.getName(), tag.getId());
        }

        // 找出需要新建的标签
        Set<String> existingTagNames = existingTags.stream()
                .map(Tag::getName)
                .collect(Collectors.toSet());

        Set<String> newTagNames = tagNames.stream()
                .filter(name -> !existingTagNames.contains(name))
                .collect(Collectors.toSet());

        // 创建新标签
        for (String tagName : newTagNames) {
            Tag newTag = new Tag();
            newTag.setName(tagName);

            tagMapper.insert(newTag);
            tagNameToIdMap.put(tagName, newTag.getId());

            log.info("创建新标签: {} (ID: {})", tagName, newTag.getId());
        }

        return tagNameToIdMap;
    }

    @Override
    public IPage<Image> pageQuery(ImageQueryDTO queryDTO) {
        // 参数校验和默认值设置
        if (queryDTO.getPageNum() == null || queryDTO.getPageNum() < 1) {
            queryDTO.setPageNum(1);
        }
        if (queryDTO.getPageSize() == null || queryDTO.getPageSize() < 1) {
            queryDTO.setPageSize(10);
        }
        if (!StringUtils.hasText(queryDTO.getSortBy())) {
            queryDTO.setSortBy("time");
        }

        // 创建分页对象
        Page<Image> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());

        // 执行分页查询
        IPage<Image> result = imageMapper.selectPageWithConditions(
                page,
                queryDTO.getTagIds(),
                queryDTO.getContentKeyword(),
                queryDTO.getFileNameKeyword(),
                queryDTO.getSortBy()
        );

        // 如果有查询结果，加载关联数据
        if (!CollectionUtils.isEmpty(result.getRecords())) {
            loadAssociatedData(result.getRecords());
        }

        return result;
    }

    /**
     * 加载关联数据（标签和文案）
     *
     * @param images 图片列表
     */
    private void loadAssociatedData(List<Image> images) {
        if (CollectionUtils.isEmpty(images)) {
            return;
        }

        // 提取图片ID列表，过滤null值
        List<Long> imageIds = images.stream()
                .map(Image::getId)
                .filter(id -> id != null)
                .distinct()
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(imageIds)) {
            return;
        }

        // 并行加载关联数据以提高性能
        try {
            // 批量加载标签数据
            loadTags(images, imageIds);

            // 批量加载文案数据
            loadCopywritings(images, imageIds);
        } catch (Exception e) {
            // 记录错误但不影响主查询结果
            System.err.println("加载关联数据时发生错误: " + e.getMessage());
            // 为所有图片设置空的关联数据
            images.forEach(image -> {
                if (image.getTags() == null) {
                    image.setTags(new ArrayList<>());
                }
                if (image.getCopywritings() == null) {
                    image.setCopywritings(new ArrayList<>());
                }
            });
        }
    }

    /**
     * 批量加载标签数据
     *
     * @param images   图片列表
     * @param imageIds 图片ID列表
     */
    private void loadTags(List<Image> images, List<Long> imageIds) {
        if (CollectionUtils.isEmpty(imageIds)) {
            images.forEach(image -> image.setTags(new ArrayList<>()));
            return;
        }
        try {
            List<TagWithImageIdDTO> tagDTOs = tagMapper.selectTagsByImageIds(imageIds);

            if (CollectionUtils.isEmpty(tagDTOs)) {
                // 如果没有标签，为每个图片设置空列表
                images.forEach(image -> image.setTags(new ArrayList<>()));
                return;
            }

            // 按图片ID分组标签，使用并行流提高性能
            Map<Long, List<Tag>> tagMap = tagDTOs.parallelStream()
                    .collect(Collectors.groupingBy(
                            TagWithImageIdDTO::getImageId,
                            Collectors.mapping(dto -> {
                                Tag tag = new Tag();
                                tag.setId(dto.getId());
                                tag.setName(dto.getName());
                                return tag;
                            }, Collectors.toList())
                    ));

            // 为每个图片设置对应的标签列表
            images.forEach(image -> {
                List<Tag> imageTags = tagMap.getOrDefault(image.getId(), new ArrayList<>());
                image.setTags(imageTags);
            });

        } catch (Exception e) {
            System.err.println("加载标签数据时发生错误: " + e.getMessage());
            // 发生异常时为所有图片设置空标签列表
            images.forEach(image -> image.setTags(new ArrayList<>()));
        }
    }

    /**
     * 批量加载文案数据
     *
     * @param images   图片列表
     * @param imageIds 图片ID列表
     */
    private void loadCopywritings(List<Image> images, List<Long> imageIds) {
        if (CollectionUtils.isEmpty(imageIds)) {
            images.forEach(image -> image.setCopywritings(new ArrayList<>()));
            return;
        }

        try {
            List<Copywriting> allCopywritings = copywritingMapper.selectByImageIds(imageIds);

            if (CollectionUtils.isEmpty(allCopywritings)) {
                // 如果没有文案，为每个图片设置空列表
                images.forEach(image -> image.setCopywritings(new ArrayList<>()));
                return;
            }

            // 按图片ID分组文案，使用并行流提高性能
            Map<Long, List<Copywriting>> copywritingMap = allCopywritings.parallelStream()
                    .collect(Collectors.groupingBy(Copywriting::getImageId));

            // 为每个图片设置对应的文案列表
            images.forEach(image -> {
                List<Copywriting> imageCopywritings = copywritingMap.getOrDefault(image.getId(), new ArrayList<>());
                image.setCopywritings(imageCopywritings);
            });

        } catch (Exception e) {
            System.err.println("加载文案数据时发生错误: " + e.getMessage());
            // 发生异常时为所有图片设置空文案列表
            images.forEach(image -> image.setCopywritings(new ArrayList<>()));
        }
    }

    @Override
    public String generateCopywriting(String imageUrl, String style, String tag, String prompt, String userId) {
        // 参数校验
        if (imageUrl == null || imageUrl.trim().isEmpty()) {
            log.error("无效请求: 图片URL为空");
            throw new IllegalArgumentException("图片URL不能为空");
        }
        if (style == null || style.trim().isEmpty()) {
            log.error("无效请求: 文案风格为空");
            throw new IllegalArgumentException("文案风格不能为空");
        }
        if (tag == null || tag.trim().isEmpty()) {
            log.error("无效请求: 图片标签为空");
            throw new IllegalArgumentException("图片标签不能为空");
        }
        if (prompt == null || prompt.trim().isEmpty()) {
            log.error("无效请求: 场景提示词为空");
            throw new IllegalArgumentException("场景提示词不能为空");
        }
        if (userId == null || userId.trim().isEmpty()) {
            log.error("无效请求: 用户ID为空");
            throw new IllegalArgumentException("用户ID不能为空");
        }

        try {
            // 创建图片生成文案请求，使用图片URL
            ImageDescriptionRequest request = new ImageDescriptionRequest(
                    imageUrl, style, tag, prompt, userId
            );

            // 调用图片生成文案服务
            ImageDescriptionResponse response = imageDescriptionClient.execute(request);

            // 解析生成的文案
            String generatedText = parseTextFromResponse(response);

            log.info("图片 {} 生成文案成功，文案长度: {}", imageUrl, generatedText.length());

            return generatedText;

        } catch (Exception e) {
            log.error("图片 {} 生成文案失败: {}", imageUrl, e.getMessage());
            throw new RuntimeException("生成文案失败: " + e.getMessage(), e);
        }
    }

    @Override
    public ImageDescriptionResponse generateCopywritingResponse(String imageUrl, String style, String tag, String prompt, String userId) {
        // 参数校验
        if (imageUrl == null || imageUrl.trim().isEmpty()) {
            log.error("无效请求: 图片URL为空");
            throw new IllegalArgumentException("图片URL不能为空");
        }
        if (style == null || style.trim().isEmpty()) {
            log.error("无效请求: 文案风格为空");
            throw new IllegalArgumentException("文案风格不能为空");
        }
        if (tag == null || tag.trim().isEmpty()) {
            log.error("无效请求: 图片标签为空");
            throw new IllegalArgumentException("图片标签不能为空");
        }
        if (prompt == null || prompt.trim().isEmpty()) {
            log.error("无效请求: 场景提示词为空");
            throw new IllegalArgumentException("场景提示词不能为空");
        }
        if (userId == null || userId.trim().isEmpty()) {
            log.error("无效请求: 用户ID为空");
            throw new IllegalArgumentException("用户ID不能为空");
        }

        try {
            // 创建图片生成文案请求，使用图片URL
            ImageDescriptionRequest request = new ImageDescriptionRequest(
                    imageUrl, style, tag, prompt, userId
            );
            log.info("请求图片生成文案服务请求体{}",request);
            // 调用图片生成文案服务
            ImageDescriptionResponse response = imageDescriptionClient.execute(request);

            if (response == null || !response.isSuccess()) {
                log.error("图片 {} 生成文案失败: 响应为空或不成功", imageUrl);
                throw new RuntimeException("生成文案失败: 服务返回无效响应");
            }

            log.info("图片 {} 生成文案成功", imageUrl);

            return response;

        } catch (Exception e) {
            log.error("图片 {} 生成文案失败: {}", imageUrl, e.getMessage());
            throw new RuntimeException("生成文案失败: " + e.getMessage(), e);
        }
    }

    /**
     * 从图片生成文案响应中解析文案文本
     *
     * @param response 图片生成文案响应
     * @return 文案文本
     */
    private String parseTextFromResponse(ImageDescriptionResponse response) {
        if (response == null || !response.isSuccess()) {
            return "";
        }

        try {
            // 直接使用ImageDescriptionResponse提供的getGeneratedText()方法
            return response.getGeneratedText();
        } catch (Exception e) {
            log.warn("解析生成文案失败: {}", e.getMessage());
            return "";
        }
    }

    @Override
    @Transactional
    public Result uploadUrl(Long userId, List<String> urls) {


        for (String url : urls) {
            // 1. 提取文件名（含扩展名）
            int lastSlashIndex = url.lastIndexOf('/');
            String fileName = url.substring(lastSlashIndex + 1); // "0e914c..._2.jpg"
            // 2. 去除扩展名（支持任意后缀）
            int lastDotIndex = fileName.lastIndexOf('.');
            String baseName = (lastDotIndex > 0) ?
                    fileName.substring(0, lastDotIndex) :
                    fileName;

            Image image = new Image();
            image.setUserId(userId);
            image.setFilePath(url);
            image.setFileName(baseName);
            image.setUploadTime(LocalDateTime.now());
            image.setVisitNum(0L);
            // 插入图片记录
            imageMapper.insert(image);

            //额外调用标签识别插入标签，传入图片ID
            generateAndSaveTagsFromUrl(url, image.getId());
        }
        return Result.success("上传成功");
    }


    @Override
    public Result deleteImage(Long imageId) {
        log.info("开始删除图片，图片ID: {}", imageId);

        try {
            // 1. 查询图片信息
            Image image = imageMapper.selectById(imageId);
            if (image == null) {
                log.warn("图片不存在，图片ID: {}", imageId);
                return Result.error(404, "图片不存在");
            }

            // 2. 删除数据库记录
            int deleteResult = imageMapper.deleteById(imageId);
            if (deleteResult == 0) {
                log.error("删除数据库记录失败，图片ID: {}", imageId);
                return Result.error(500, "删除失败");
            }

            log.info("图片删除成功，图片ID: {}, 文件路径: {}", imageId, image.getFilePath());
            return Result.success();

        } catch (Exception e) {
            log.error("删除图片时发生异常，图片ID: {}", imageId, e);
            return Result.error(500, "删除图片失败: " + e.getMessage());
        }
    }

    /**
     * 根据图片URL生成标签并存入标签和标签图片关联表
     *
     * @param imageUrl 图片URL
     * @param imageId 图片ID（可选，如果为null则不创建关联）
     * @return 生成的标签列表
     */
    @Transactional(rollbackFor = Exception.class)
    public List<String> generateAndSaveTagsFromUrl(String imageUrl, Long imageId) {
        if (imageUrl == null || imageUrl.trim().isEmpty()) {
            log.error("图片URL不能为空");
            throw new IllegalArgumentException("图片URL不能为空");
        }

        try {
            log.info("开始为图片URL生成标签: {}", imageUrl);

            // 1. 调用classifyClient获取标签
            ClassifyRequest request = new ClassifyRequest(imageUrl);
            ClassifyResponse response = classifyClient.execute(request);

            // 2. 解析标签数据
            List<String> tagNames = parseTagsFromResponse(response);
            if (tagNames.isEmpty()) {
                log.warn("图片 {} 未识别到任何标签", imageUrl);
                return Collections.emptyList();
            }

            log.info("图片 {} 识别到 {} 个标签: {}", imageUrl, tagNames.size(), tagNames);

            // 3. 确保标签存在于数据库中，不存在则创建
            Set<String> tagNameSet = new HashSet<>(tagNames);
            Map<String, Long> tagNameToIdMap = ensureTagsExist(tagNameSet);

            // 4. 如果提供了imageId，创建图片标签关联
            if (imageId != null) {
                for (String tagName : tagNames) {
                    Long tagId = tagNameToIdMap.get(tagName);
                    if (tagId != null) {
                        // 检查关联是否已存在，避免重复插入
                        LambdaQueryWrapper<ImageTag> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.eq(ImageTag::getImageId, imageId)
                                   .eq(ImageTag::getTagId, tagId);
                        
                        if (imageTagMapper.selectCount(queryWrapper) == 0) {
                            ImageTag imageTag = new ImageTag();
                            imageTag.setImageId(imageId);
                            imageTag.setTagId(tagId);
                            imageTagMapper.insert(imageTag);
                            
                            log.debug("创建图片标签关联: imageId={}, tagId={}, tagName={}", 
                                    imageId, tagId, tagName);
                        } else {
                            log.debug("图片标签关联已存在: imageId={}, tagId={}, tagName={}", 
                                    imageId, tagId, tagName);
                        }
                    }
                }
                
                log.info("为图片 {} 创建了标签关联，共 {} 个标签", imageId, tagNames.size());
            }

            return tagNames;

        } catch (Exception e) {
            log.error("为图片URL {} 生成标签失败: {}", imageUrl, e.getMessage(), e);
            throw new RuntimeException("生成标签失败: " + e.getMessage(), e);
        }
    }
}